<?php
/**
 * Celebrio FileSystem module
 *
 * @copyright  Copyright (c) 2011 Celebrio Software
 * @package    Celebrio
 * @subpackage FileSystem
 */
namespace Celebrio\FileSystem;

use Nette\Object;
use Nette\Environment;

use dibi;

use Celebrio\Core\IModuleInit;
use Celebrio\Core\DummyInit;
use Celebrio\Core\ServiceProvider;
use Celebrio\Core\DDL;

use Celebrio\FileSystem\VirtualFile;
use Celebrio\FileSystem\FileNameCollisionException;


/**
 * Initialization methods for VirtualFileSystem. Some methods are called 
 * every time when any FS module is activated, some methods only once
 * when the first module is activated. This will be specified (TODO).
 *
 * @author pavel
 */
class VfsInit extends DummyInit implements IModuleInit {

    private $fpermissions = "fpermissions";
    private $fprivileges = "fprivileges";
    private $files = "files";
    private $mimetypes = "mimetypes";
    
    private $files_storages = "files_storages";
    
    private $user;
    
    public function __construct() {
        $this->user = Environment::getUser();
    }

    public function install(array $configuration = array()) {
        
        $dbname = ServiceProvider::getServiceName("Celebrio-Database-IDatabase");
        DDL::execute(__DIR__ . "/sql/FS_$dbname.sql");
        
        $mimetypeId = VirtualFile::createMimeType(DataFile::DIR);
        
        
        //$driver = ServiceProvider::getServiceName("Celebrio-FileSystem-Drivers-IDriver");
        $driver = "defaultStorage";
        $storageId = $this->initDriverStorage(strtolower($driver)); //temporary
        $this->initFilePrivileges();
        $this->initRootDirectory($mimetypeId, $storageId);
        
    }

    /**
     * Creates the Root directory entry in the database (files table).
     * This method should be called only when initlizing first module.
     *
     * @param int $mimetypeId ID of the directory mimetype belonging to
     *            the driver which is currently initialized
     * @param String $virtualRoot the virtual root directory name
     */
    public function initRootDirectory($mimetypeId, $storageId) {
        $rootAlreadyExisting = dibi::fetch("
                SELECT * FROM [$this->files]
                WHERE [name_file]=%s AND [id_parent] IS NULL 
                AND [id_mimetype]=%s AND [id_files_storage]=%s",
                VirtualFile::VIRTUAL_ROOT, $mimetypeId, $storageId);
        if ($rootAlreadyExisting) throw new FileNameCollisionException(_("The root directory record already exists in the database."));
        
        $userId = $this->user->getIdentity()->data["id"];
        
        dibi::query("INSERT INTO [$this->files]
                ([id_user],[id_mimetype],[name_file],[id_files_storage]) VALUES
                (%iN, %iN, %sN, %iN)", $userId, $mimetypeId, VirtualFile::VIRTUAL_ROOT, $storageId);
    }

    /**
     * Creates the basic privileges for VFS.
     */
    public function initFilePrivileges() {
        $privileges = $this->filePrivileges();
        foreach ($privileges as $privilege) {
            dibi::query("INSERT INTO [$this->fprivileges](name) VALUES (%s)", $privilege);
        }
    }
    
    
    /**
     * Checks the DB if the mimetype of the driver directory (driver given as parameter)
     * has already been created. If yes, returns its ID. If not, the method
     * creates the record and returns its ID.
     * 
     * @param String $driver the driver name, e.g "local"
     * @return int MimetypeID the ID of the dir/driver mimetype
     */
    public function initDriverStorage($driver) {
        $exists = dibi::fetch("
                SELECT id_files_storage FROM [$this->files_storages]
                WHERE [name_files_storage]=%s", $driver);
        if ($exists) {
            $storageId = $exists->id_files_storage;
        } else {
            dibi::query("
                INSERT INTO [files_storages]([name_files_storage])
                VALUES (%sN)", $driver);
            $storageId = dibi::getInsertId();
        }
        return $storageId;
    }
    
    
    /**
     * Defines the list of the implemented privileges.
     *
     * Privileges list [in czech]:
     * 
     * Procházet složku / Spouštět soubory X
     * Zobrazovat obsah složky / Číst data R
     * Číst atributy = hidden, protected, encrypted, locked
     * Write
     * Zapisovat atributy
     * Odstraňovat
     * Číst oprávnění ostatnich (pridelovat opravneni muze jen vlastnik)
     * Převzetí vlastnictví
     *
     * @return array(String)
     */
    private function filePrivileges() {
        return array (
            "read",
            "read attributes",
            "write",
            "write attributes",
            "execute",
            "delete",
            "read permissions",
            "take ownership",
        );
    }
}
